#include <QtWidgets>

#include "view/mainwindow.h"
#include "view/widget.h"
#include "view/lightingdialog.h"
#include "view/heightmapdialog.h"

#include "model/regular.h"
#include "model/scene.h"

#include "method/projection.h"
#include "method/shading.h"
#include "method/wireframe.h"

// TODO remover include
// includes temporarios
#include <QDebug>
// fim dos includes temporarios

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
    this->scene = new Scene();
    this->randomize();

    this->setCentralWidget( new Widget(this) );
    this->centralWidget()->setFocus();

    this->initFileMenu();
    this->initViewMenu();
    this->initLightingMenu();

    this->resize(800,600);
    this->setMinimumSize(640, 480);
}

MainWindow::~MainWindow() {}

Scene *MainWindow::getScene() {
    return scene;
}

Widget *MainWindow::getWidget() {
    return (Widget*) this->centralWidget();
}

void MainWindow::open(QString filename, unsigned int width, unsigned int height, unsigned int rows, unsigned int columns) {
    this->setGround(new RegularObject(filename, width, height, rows, columns));
}

void MainWindow::initFileMenu(){
    QMenuBar *menubar = this->menuBar();

    QMenu *filemenu = menubar->addMenu(tr("&Arquivo"));

    QAction *newaction = filemenu->addAction(tr("&Novo"));
    newaction->setShortcut(QKeySequence("CTRL+N"));
    QObject::connect(newaction, SIGNAL(triggered()), this, SLOT(randomize()));

    filemenu->addSeparator();

    QAction *openaction = filemenu->addAction(tr("&Abrir"));
    openaction->setShortcut(QKeySequence("CTRL+O"));
    QObject::connect(openaction, SIGNAL(triggered()), this, SLOT(open()));

    QAction *openFromImageAction = filemenu->addAction(tr("&Abrir de imagem"));
    openFromImageAction->setShortcut(QKeySequence("CTRL+SHIFT+O"));
    QObject::connect(openFromImageAction, SIGNAL(triggered()), this, SLOT(openFromImage()));

    QAction *saveaction = filemenu->addAction(tr("&Salvar"));
    saveaction->setShortcut(QKeySequence("CTRL+S"));
    QObject::connect(saveaction, SIGNAL(triggered()), this, SLOT(save()));

    filemenu->addSeparator();

    QAction *quitaaction = filemenu->addAction(tr("&Quit"));
    quitaaction->setShortcut(QKeySequence("CTRL+Q"));
    QObject::connect(quitaaction, SIGNAL(triggered()), this, SLOT(close()));
}

void MainWindow::initViewMenu() {
    QMenu *viewmenu = this->menuBar()->addMenu(tr("&Visão"));
    QActionGroup *shadingGroup = new QActionGroup(viewmenu);

    QAction *wireframe = viewmenu->addAction(tr("Wireframe"));
    QObject::connect(wireframe, SIGNAL(triggered()), this, SLOT(toWireframe()));
    wireframe->setActionGroup(shadingGroup);
    wireframe->setCheckable(true);

    QAction *zBuffer = viewmenu->addAction(tr("Wireframe com ocultação de face"));
    QObject::connect(zBuffer, SIGNAL(triggered()), this, SLOT(toZBuffer()));
    zBuffer->setActionGroup(shadingGroup);
    zBuffer->setCheckable(true);

    QAction *constant = viewmenu->addAction(tr("Sombreamento Constante"));
    QObject::connect(constant, SIGNAL(triggered()), this, SLOT(toConstantShading()));
    constant->setActionGroup(shadingGroup);
    constant->setCheckable(true);

    QAction *gouraud = viewmenu->addAction(tr("Sombreamento Gouraud"));
    QObject::connect(gouraud, SIGNAL(triggered()), this, SLOT(toGouraudShading()));
    gouraud->setActionGroup(shadingGroup);
    gouraud->setCheckable(true);
    gouraud->setChecked(true);
    toGouraudShading();

    viewmenu->addSeparator();
    QActionGroup *projectionGroup = new QActionGroup(viewmenu);

    QAction *perspective = viewmenu->addAction(tr("Visão Perspectiva"));
    QObject::connect(perspective, SIGNAL(triggered()), this, SLOT(toPerspectiveProjection()));
    perspective->setActionGroup(projectionGroup);
    perspective->setCheckable(true);
    perspective->setChecked(true);
    this->toPerspectiveProjection();

    QAction *isometric = viewmenu->addAction(tr("Visão Isométrica"));
    QObject::connect(isometric, SIGNAL(triggered()), this, SLOT(toIsometrictProjection()));
    isometric->setActionGroup(projectionGroup);
    isometric->setCheckable(true);

    viewmenu->addSeparator();

    QAction *resetobserveraction = viewmenu->addAction(tr("&Resetar Visão"));
    resetobserveraction->setShortcut(QKeySequence("SHIFT+N"));
    QObject::connect(resetobserveraction, SIGNAL(triggered()), this, SLOT(resetView()));
}

void MainWindow::initLightingMenu() {
    QMenu *lightingMenu = this->menuBar()->addMenu(tr("&Iluminação"));

    QAction *smoothAaction = lightingMenu->addAction(tr("&Suavizar malha"));
    smoothAaction->setShortcut(QKeySequence("CTRL+SHIFT+S"));
    QObject::connect(smoothAaction, SIGNAL(triggered()), this, SLOT(smoothGround()));

    lightingMenu->addSeparator();

    QAction *lightingProperties = lightingMenu->addAction(tr("Propriedades"));
    QObject::connect(lightingProperties, SIGNAL(triggered()), this, SLOT(lightingProperties()));
    lightingProperties->setShortcut(QKeySequence("CTRL+I"));
}

void MainWindow::setProjection(Projection *projection) {    // TODO.. ARRUMAR NA ILUMINACAO CONSTANTE IMG APARECE INVERTIDA
    Widget* widget = this->getWidget();
    Projection* oldprojection = widget->getProjection();

    if ( oldprojection )
        delete oldprojection;

    widget->setProjection(projection);
}

void MainWindow::setShading(Filler *shading) {
    Widget* widget = this->getWidget();
    Filler* oldshading = widget->getShading();

    if ( oldshading )
        delete oldshading;

    widget->setShading(shading);
}

void MainWindow::setGround(Object *ground) {
    Object *o = scene->getGround();
    if ( o )
        delete o;
    scene->setGround(ground);
}

void MainWindow::open() {
    QString filename = QFileDialog::getOpenFileName(this,
                                 tr("Abrir arquivo"),
                                 tr(""),
                                 tr("Arquivos Golem (*.golem)")
                                 );

    if ( !filename.isEmpty() ) {
        this->setGround(new Object(filename.toStdString()));
    }
}

void MainWindow::openFromImage() {
    HeightmapDialog *dialog = new HeightmapDialog(this);
    dialog->show();
    connect(this, SIGNAL(destroyed()), dialog, SLOT(close()));
}

void MainWindow::save() {
    QString filename = QFileDialog::getSaveFileName(this,
                                 tr("Salvar arquivo"),
                                 tr(""),
                                 tr("Arquivos Golem (*.golem)")
                                 );

    if ( !filename.isEmpty() ) {
        Object *o = scene->getGround();
        if ( o )
            o->save(filename.toStdString());
    }
}

void MainWindow::randomize() {
    this->setGround(new RegularObject());
}

void MainWindow::resetView() {
    this->getWidget()->resetView();
}

void MainWindow::smoothGround() {
    this->setGround(reinterpret_cast<RegularObject*>(scene->getGround())->smooth());
}

void MainWindow::toIsometrictProjection() {
    this->setProjection(new IsometrictProjection());
}

void MainWindow::toPerspectiveProjection() {
    this->setProjection(new PerspectiveProjection());
}

void MainWindow::toZBuffer() {
    this->setShading(new ZBuffer());
}

void MainWindow::toWireframe() {
    this->setShading(new Wireframe());
}

void MainWindow::toConstantShading() {
    this->setShading(new ConstantShading());
}

void MainWindow::toGouraudShading() {
    this->setShading(new GouraudShading());
}

void MainWindow::lightingProperties() {
    LightingDialog *l = new LightingDialog(this->scene);
    l->show();
}

